package com.grupo83.bbicing.blackberry;

import java.io.*;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.microedition.io.*;

import net.rim.device.api.system.CoverageInfo;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.WLANInfo;

public class HTTPConnect extends Thread
{
	//Received parameters
	private String _url;
	private boolean _isPost = false;
	private String _data;
	private ObserverInterface _observer;
	
	//Internal use variables
	private HttpConnection _httpConnection;
	private Hashtable _headers = new Hashtable();
	private boolean _stopRequest = false;
	
	//Output variables
	private InputStream _is = null;
	private String _res = null;

	/**
	 * Construct an HTTPConnection object to be used to connect to
	 * a remote server
	 *
	 * @param  url an absolute URL to connect to
	 * 
	 * @param  isPost if the connection should use the POST method. False will set it to GET
	 *  
	 * @param  data the data to use for get/post
	 * 
	 * @param  observer the observer to listen for thread updates
	 *                  
	 */
	public HTTPConnect( String url, boolean isPost, String data, ObserverInterface observer )
	{
		//Set isPost variable to check on run method
		_isPost = isPost;
		_observer = observer;
		
		//Configure url and data depending on if we are doing a get or a post
		if( _isPost )
		{
			_url = url;
			_data = data;
		}
		else
			_url = url + "?" + data;
		
		//Create connection
		try
		{
			String cnct = getConnectionString();
			if( cnct != null )
				_httpConnection = (HttpConnection) Connector.open( _url + getConnectionString() );
			else
			{
		        observerError(ObserverInterface.CANCELLED, "No connection available");
		        _stopRequest = true; // Will no longer tell Observer anything
		        //this.interrupt(); // Give our Thread a kick
			}
		}
		catch ( Exception e )
		{
	        observerError(ObserverInterface.CANCELLED, "No connection available");
	        _stopRequest = true; // Will no longer tell Observer anything
	        //this.interrupt(); // Give our Thread a kick
		}
	}
	
	public void run()
	{
		try
		{
			//Add default headers to header hashtable
			defaultHeaders();
		
			//ByteArrayOutputStream to write response to
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			
			//Push header table to connection
			Enumeration keys = _headers.keys();
						
			while( keys.hasMoreElements() )
			{
				String ckey = (String)keys.nextElement();
				_httpConnection.setRequestProperty( ckey, (String)_headers.get( ckey ) );
			}

			//If posting add any necessary information. The same with get
			if( _isPost )
			{
				_httpConnection.setRequestMethod( HttpConnection.POST );
				_httpConnection.setRequestProperty( "Content-Length", Integer.toString( _data.length() ) );
				_httpConnection.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" );
				
				OutputStream os = _httpConnection.openOutputStream();
				os.write( _data.getBytes() );
				os.close();
			}
			else
			{
				_httpConnection.setRequestMethod(HttpConnection.GET);
			}

			if ( _httpConnection.getResponseCode() == HttpConnection.HTTP_OK )
			{
				_is = _httpConnection.openInputStream();

				observerResponse( _is );
				int ch;
				while ((ch = _is.read()) != -1)
				{
					bos.write(ch);
				}
				_res = bos.toString();
				observerResponseString( _res );
			}
			else
			{
				_res = Integer.toString( _httpConnection.getResponseCode() );
				observerError( _httpConnection.getResponseCode(), _res );
			}
		}
		catch ( Exception e )
		{
		}
	}
	
	/**
	 * Add a header for the new connection
	 *
	 * @param  name the header name
	 * 
	 * @param  value the header value associated to the provided name
	 */
	public void addHeader( String name, String value )
	{
		_headers.put( name, value );
	}
	
	private void defaultHeaders()
	{
		_headers.put( "User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0" );
	}
	
    public void stop() {
        // Tell our observer
        observerError(ObserverInterface.CANCELLED, "Cancelled by User");
        _stopRequest = true; // Will no longer tell Observer anything
        this.interrupt(); // Give our Thread a kick
    }

    private void observerStatusUpdate( final int status, final String statusString ) {
        if ( !_stopRequest ) {
            _observer.processStatusUpdate( status, statusString );
        }
    }

    private void observerError( int errorCode, String errorMessage ) {
        if ( !_stopRequest ) {
            _observer.processError( errorCode, errorMessage );
        }
    }

    private void observerResponse(InputStream reply) {
        if ( !_stopRequest ) {
            _observer.processResponse( reply );
        }
    }
    
    private void observerResponseString(String reply) {
        if ( !_stopRequest ) {
            _observer.processResponseString( reply );
        }
    }

	
	/**
	 * Determines what connection type to use and returns the necessary string to use it.
	 * @return A string with the connection info
	 */
	private static String getConnectionString()
	{
	    // This code is based on the connection code developed by Mike Nelson of AccelGolf.
	    // http://blog.accelgolf.com/2009/05/22/blackberry-cross-carrier-and-cross-network-http-connection
	    String connectionString = null;               
	 
	    // Simulator behavior is controlled by the USE_MDS_IN_SIMULATOR variable.
	    if(DeviceInfo.isSimulator())
	    {
	            /*if(UploaderThread.USE_MDS_IN_SIMULATOR)
	            {
	                    //logMessage("Device is a simulator and USE_MDS_IN_SIMULATOR is true");
	                    connectionString = ";deviceside=false";
	            }
	            else
	            {*/
	                    //logMessage("Device is a simulator and USE_MDS_IN_SIMULATOR is false");
	                    connectionString = ";deviceside=true";
	            //}
	    }                                       
	 
	    // Wifi is the preferred transmission method
	    else if(WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED)
	    {
	        //logMessage("Device is connected via Wifi.");
	        connectionString = ";interface=wifi";
	    }
	 
	    // Is the carrier network the only way to connect?
	    else if((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_DIRECT) == CoverageInfo.COVERAGE_DIRECT)
	    {
	        //logMessage("Carrier coverage.");
	 
	        /*String carrierUid = getCarrierBIBSUid();
	        if(carrierUid == null)
	        {
	            // Has carrier coverage, but not BIBS.  So use the carrier's TCP network
	            //logMessage("No Uid");
	            connectionString = ";deviceside=true";
	        }
	        else
	        {*/
	            // otherwise, use the Uid to construct a valid carrier BIBS request
	            //logMessage("uid is: " + carrierUid);
	            //connectionString = ";deviceside=false;connectionUID="+carrierUid + ";ConnectionType=mds-public";
	            connectionString = ";deviceside=false;ConnectionType=mds-public";
	        //}
	    }               
	 
	    // Check for an MDS connection instead (BlackBerry Enterprise Server)
	    else if((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_MDS) == CoverageInfo.COVERAGE_MDS)
	    {
	        //logMessage("MDS coverage found");
	        connectionString = ";deviceside=false";
	    }
	    	 
	    // If there is no connection available abort to avoid bugging the user unnecssarily.
	    else if(CoverageInfo.getCoverageStatus() == CoverageInfo.COVERAGE_NONE)
	    {
	        //logMessage("There is no available connection.");
	    }
	 
	    // In theory, all bases are covered so this shouldn't be reachable.
	    else
	    {
	        //logMessage("no other options found, assuming device.");
	        //connectionString = ";deviceside=true";
	    	connectionString = ";ConnectionUID=WAP2 trans";
	    }       
	 
	    return connectionString;
	}
	 
	/**
	 * Looks through the phone's service book for a carrier provided BIBS network
	 * @return The uid used to connect to that network.
	 */
	/*private static String getCarrierBIBSUid()
	{
	    ServiceRecord[] records = ServiceBook.getSB().getRecords();
	    int currentRecord;
	 
	    for(currentRecord = 0; currentRecord < records.length; currentRecord++)
	    {
	    	if(records[currentRecord].getCid().toLowerCase().equals("ippp"))
	    	{
	    		if(records[currentRecord].getName().toLowerCase().indexOf("bibs") >= 0)
	            {
	                return records[currentRecord].getUid();
	            }
	        }
	    }
	    return null;
	}*/
}

